package main

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
	"github.com/shirou/gopsutil/process"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"sort"
	"strconv"
	"strings"
	"syscall"
)

var port string
var token string
var Table []string = []string{"小代", "上等马", "中等马", "小丑", "纯纯的FW"}

func main() {
	port, token = GetPortandToken()
	GUI()
}

func GUI() {
	t := &myTheme{}
	t.SetFonts("./songti.ttf", "")

	myApp := app.New()

	myWindow := myApp.NewWindow("LoLHelper")
	myApp.Settings().SetTheme(t)
	txtBound := binding.NewString()
	txtWid := widget.NewEntryWithData(txtBound)
	txtWid.MultiLine = true
	// we can disable the Entry field so the user can't modify the text:
	txtWid.Disabled()
	txtWid.Resize(fyne.NewSize(500, 200))
	txtBound.Set("请一定要在选英雄界面再在点击按钮")
	button := widget.NewButton("Get History", func() {
		res := OutputAllSummonerInRoom()
		txtBound.Set(res)
	})
	content := container.NewVBox(button, txtWid)
	myWindow.SetContent(content)
	myWindow.Resize(fyne.NewSize(500, 100))

	myWindow.ShowAndRun()
}
func OutputAllSummonerInRoom() string {
	roomName := GetRoomInfo()              //1.获取房间名
	sic := GetSummonerInRoomChat(roomName) //2。获取房间内玩家ID
	sif := make([]Summoner, 0, 5)
	for i, summoner := range sic {
		s := GetSummonerInfo(summoner.SummonerId) //3.根据ID获取每个用户的信息
		sif = append(sif, s)
		history := GetMatchHistoryInfo(s.Puuid, 0, 5) //4.获取每个玩家前5条最新的战绩
		AnalyzeInfo(history, &sif[i])                 //5.分析每个玩家战绩
	}
	sort.Slice(sif, func(i, j int) bool { //6.排序
		return sif[i].Kda > sif[j].Kda
	})
	var res string
	for x, summoner := range sif { //7.输出结果
		res += fmt.Sprintf("我方%s:%s KDA:%.2f 最近%d场战绩为 ", Table[x], summoner.DisplayName, summoner.Kda, len(summoner.History))
		for i := len(summoner.History) - 1; i >= 0; i-- {
			v := summoner.History[i]
			res += fmt.Sprintf(" %d/%d/%d ", v.Kill, v.Deaths, v.Assist)
		}
		res += fmt.Sprintf("\n")
	}
	Output(res)
	return res
}

type SummonerHistory struct {
	Kill   int `json:"kills"`
	Deaths int `json:"deaths"`
	Assist int `json:"assists"`
}

//分析单个用户的战绩 kda
func AnalyzeInfo(res []byte, summoner *Summoner) {
	var sh SummonerHistory
	shs := make([]SummonerHistory, 0, 5)
	for i := 0; i < 5; i++ {
		l := bytes.Index(res, []byte("\"stats\":")) //stats的位置
		if l == -1 {
			break
		}
		l += 8 //stats的左括号{
		res = res[l:]
		r := bytes.Index(res, []byte("}"))
		json.Unmarshal(res[:r+1], &sh)
		shs = append(shs, sh)
		res = res[r+1:]
	}
	if len(shs) == 0 {
		Output("该用户近期无游戏或战绩不可见的小丑")
		return
	}
	cnt := len(shs)
	kda, kill, death, assist := 0.0, 0, 0, 0
	for i := cnt - 1; i >= 0; i-- {
		v := shs[i]
		kill += v.Kill
		death += v.Deaths
		assist += v.Assist
	}
	if death == 0 {
		death = 1
	}
	kda = float64(kill+assist) / float64(death)
	summoner.Kda = kda
	summoner.History = shs
}

//获取某个用户的战绩从begin~end
func GetMatchHistoryInfo(puuid string, beginIndex, endIndex int) []byte {
	begin := strconv.Itoa(beginIndex)
	end := strconv.Itoa(endIndex)
	res := GetRes("lol-match-history/v1/products/lol/" + puuid + "/matches?begIndex=" + begin + "&endIndex=" + end)
	return res
}

type Summoner struct {
	AccountId   int64  `json:"accountId"`
	DisplayName string `json:"displayName"`
	Puuid       string `json:"puuid"`
	Kda         float64
	History     []SummonerHistory
}

//根据SummonerId获得玩家信息
func GetSummonerInfo(summonerId string) Summoner {
	res := GetRes("lol-summoner/v1/summoners/" + summonerId)
	var summoner Summoner
	json.Unmarshal(res, &summoner)
	return summoner
}

type SummonerInChatRoom struct {
	SummonerId string `json:"fromId"` //聊天室内用户的ID
}

//获取房间聊天室的玩家ID
func GetSummonerInRoomChat(chatRoomName string) []SummonerInChatRoom {
	body := GetRes("lol-chat/v1/conversations/" + chatRoomName + "/messages")
	sic := make([]SummonerInChatRoom, 0, 5)
	for i := 0; i < 5; i++ {
		if len(body) == 0 {
			break
		}
		l := bytes.Index(body, []byte("{"))
		r := bytes.Index(body, []byte("}"))
		var s SummonerInChatRoom
		json.Unmarshal(body[l:r+1], &s)
		sic = append(sic, s)
		body = body[r+2:]
	}
	return sic
}

type RoomInfo struct {
	Chatdetails ChatDetails `json:"chatDetails"`
}
type ChatDetails struct {
	ChatRoomName string `json:"chatRoomName"`
}

var roominfo RoomInfo //你所在的房间信息
//获取房间信息
func GetRoomInfo() string {
	body := GetRes("lol-champ-select/v1/session")
	json.Unmarshal(body, &roominfo)
	split := strings.Split(roominfo.Chatdetails.ChatRoomName, "@")
	roominfo.Chatdetails.ChatRoomName = split[0]
	return split[0]
}

//获取登录的个人角色信息
func GetCurrentSummoner() {
	GetRes("lol-summoner/v1/current-summoner")
}

func GetRes(url string) []byte {
	//创建url
	url = "https://127.0.0.1:" + port + "/" + url
	//fmt.Printf("----------getRes------url: %s  -----\n", url)
	//创建request
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		fmt.Println("request error", err)
	}
	//这里请注意，使用 InsecureSkipVerify: true 来跳过证书验证
	client := &http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}}
	//base64编码
	tokens := base64.StdEncoding.EncodeToString([]byte("riot:" + token))
	//设置token
	request.Header.Add("Authorization", "Basic "+tokens)
	resp, err := client.Do(request)
	if err != nil {
		fmt.Println("response error", err)
	}
	defer resp.Body.Close()
	//读取结果 一定要ReadAll一下
	body, _ := ioutil.ReadAll(resp.Body)
	client.CloseIdleConnections()
	return body
}

//获得LeagueClientUx.exe启动参数中的端口和token
func GetPortandToken() (port string, token string) {
	processes, _ := process.Processes()
	var pro *process.Process
	for _, p := range processes {
		name, _ := p.Name()
		if name == "LeagueClientUx.exe" {
			pro = p
			break
		}
	}
	if pro == nil {
		return "", ""
	}
	//获得命令行集合
	cmdlineSlice, _ := pro.CmdlineSlice()
	len1 := len("--remoting-auth-token=")
	len2 := len("--app-port=")
	//检索得到端口和token
	for _, str := range cmdlineSlice {
		if strings.Contains(str, "--remoting-auth-token") {
			token = str[len1+1 : len(str)-1] //+1 是因为 字符串“token” 还有一个标点符号
			fmt.Println("token is ", token)
		}
		if strings.Contains(str, "--app-port") {
			port = str[len2+1 : len(str)-1]
			fmt.Println("port is ", port)
			break
		}
	}
	return
}
func Pause() {
	quit := make(chan os.Signal, 1) // 创建一个接收信号的通道
	// kill 默认会发送 syscall.SIGTERM 信号
	// kill -2 发送 syscall.SIGINT 信号，我们常用的Ctrl+C就是触发系统SIGINT信号
	// kill -9 发送 syscall.SIGKILL 信号，但是不能被捕获，所以不需要添加它
	// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信号转发给quit
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞
	<-quit                                               // 阻塞在此，当接收到上述两种信号时才会往下执行
}
func Output(a ...any) {
	fmt.Println("--------分割线--------")
	fmt.Printf("%+v \n", a)
}
